if (!CreoleWiki) { var CreoleWiki = {}; }

/*
 * url: the full url including hash
 * options: main: div to show main content
 * 			menu: div to show menu
 * 			input: input textarea
 * 			iframeAjax: if to use iframe ajax, XMLHttpRequest seems only support UTF-8 using file protocal
 * 			crlf: if to use crlf, useful on windows
 * 			encoding: default to UTF-8
 * 			wikiSuffix: default to .txt, prevent IE asking for download or save file when using iframeAjax
 */
CreoleWiki.Site = function(url, options){
	this.url = url.replace(/\\/g, '/');
	
	this.siteTitle = document.title;

	this.parseUrl();
	
	this.initOptions(options);
}

CreoleWiki.Site.prototype = {
	url: null,
	siteTitle: null,
	creoleUrl: null,
	creolePath: null,
	creoleParam: null,
	
	absolute: null,
	wikiName: null,
	sitePathParam: null,
	sitePath: null,
	siteUrl: null,
	originalOptions: null,
	options: {},
	creole: null,
	suffix: null,
	menu: null,
	main: null,
	input: null,
	loaded: false,
	parseUrl: function(){
	    var qindex = this.url.lastIndexOf('#');
	    this.creoleUrl = qindex >= 0 ? this.url.substring(0, qindex) : this.url;
	    this.creolePath = this.creoleUrl.substring(0, this.creoleUrl.lastIndexOf('/') + 1);
		this.creoleParam = decodeURI(this.url.substring(this.creoleUrl.length + 1));
		
		this.absolute = this.creoleParam.substring(0, 1) == '/';
		var wikiNameIndex = this.creoleParam.lastIndexOf('/');
		this.sitePathParam = wikiNameIndex >= 0 ? this.creoleParam.substring(0, wikiNameIndex + 1) : '';
		this.sitePath = this.absolute ? this.sitePathParam : this.creolePath + this.sitePathParam;
		this.wikiName = this.creoleParam.substring(this.sitePathParam.length);
		this.siteUrl = this.creoleUrl + '#' + this.sitePathParam;
	},
	
	initOptions: function(options){
		this.originalOptions = options || {};	
				
		$.extend(this.options, this.originalOptions);
		
		this.main = this.options.main || $('#main').get(0);
		if (!this.main){
			CreoleWiki.error("Please define main content panel!");
		}
		this.menu = this.options.menu || $('#menu').get(0);
		if (!this.menu){
			CreoleWiki.error("Please define menu content panel!");
		}
		this.input = this.options.input || $('#input').get(0);
		if (!this.input){
			CreoleWiki.error("Please define input text area!");
		}
		this.suffix = this.options.wikiSuffix || '.txt';
		if (this.suffix.charAt(0) != '.'){
			this.suffix = '.' + this.suffix;
		}
	},
	
	getFullWikiName: function(){
		return '#' + this.sitePathParam + this.wikiName;
	},
	
	linkFormat: function(wiki){
		var link = wiki;
		if (wiki.charAt(0) != '#'){
			var link = '#' + this.sitePathParam + wiki;
			var tmpWiki;
			while (link != tmpWiki) {
				tmpWiki = link;
				link = link.replace(/\w+\/\.\.\//g, '');
			} 
		}
		return encodeURI(link);
	},
	
	initSite: function(wiki){
		if (wiki.charAt(0) == '#'){
			
		}
	},
	
	start: function(){
		window.site = this;
		
	    CreoleWiki.Moniter.start();
	},
	
	loadWiki: function (wiki, changeHash){
		if (wiki == '#Special:Favorite'){
			$(this.main).html(CreoleWiki.Favorite.getFavorite());
			return;
		}
		
		if (wiki == '#Special:Home'){
			wiki =  CreoleWiki.Favorite.getHome();
		}
		
		if (!wiki && !this.sitePathParam){
			wiki = CreoleWiki.Favorite.getHome();
		}
		
		var wikiUrl = this.creoleUrl + this.linkFormat(wiki);
		var wikiSite = new CreoleWiki.Site(wikiUrl, this.originalOptions);
		
		if (changeHash){
			window.location.hash = wikiSite.getFullWikiName();
			return;
		}
		
		if (wikiSite.sitePathParam == this.sitePathParam){
			this.load(wikiSite.wikiName);
		} else{
			wikiSite.load();
		}
	},

	load: function(wiki){		
		if (! this.loaded){
			this.loaded = true;
			window.site = this;
		    this.creole = new Parse.Simple.Creole( {
		    	site: this,
		        forIE: document.all,
		        interwiki: {
		            WikiCreole: 'http://www.wikicreole.org/wiki/',
		            Wikipedia: 'http://en.wikipedia.org/wiki/'
		        },
		        linkFormat: function(link, options, a) { 
		        	// $(a).click(function(){options.site.loadWiki(link)});
		        	// return "javascript:void(0);";
		        	return options.site.linkFormat(link);
		        },
		        imgFormat: function(src, options) {
		        	return src.substring(0, 1) == '/' || src.indexOf(':') > 0 ?
		        			src : options.site.sitePathParam + src;
		        }
		    });			
		    
		    // load menu
		    this.loadContent('wikiConfig', this.menu, function(data, wiki, contentPane, site){
		    	var menuDiv = $(contentPane);
		    	menuDiv.addClass('jquerycssmenu');
		    	jquerycssmenu.buildmenu(menuDiv.attr('id'));
		    	var menu = menuDiv.find('ul:first');
		    	menu.siblings().hide();
		    	menuDiv.append('<br style="clear: left" />');
		    	
		    	var configText = $('#menu>pre').text();
		    	if (configText){
		    		try{
			    		eval('var _wikiconfig = {' + configText + '}');
			    		var config = _wikiconfig;
			    		if (config.siteTitle){
			    			site.siteTitle = config.siteTitle;
			    		}
			    		if (config.interwiki){
			    			$.extend(config.interwiki, site.creole.options.interwiki);
			    		}
			    		$.extend(site.creole.options, config);
		    		} catch (e){
		    			alert(e);
		    		}
		    	}
		    });
		}

	    // load the wiki page
	    this.loadContent(wiki || this.wikiName);
	    
	    // bind input event
	    $(this.input).unbind('keyup').bind('keyup', {site:this}, function(e) {
	        e.data.site.render(this.value);
	    });
	},

	loadContent: function (wiki, contentPane, callBack){	
	    var wiki = decodeURI(wiki || 'index');
	    var site = this;
	    var wikiPath = this.sitePath + wiki + this.suffix;
	    var contentHandler = function(data){
			site.render(data, contentPane);
			if (!contentPane || contentPane === site.main){
	    		site.input.value = data;
				document.title = wiki == 'index' ? site.siteTitle : wiki + ' - ' + site.siteTitle;
				site.wikiName = wiki;
			}
			
			if (callBack instanceof Function){
				callBack(data, wiki, contentPane, site);
			}
		};
		if (this.options.iframeAjax){
			// ajax only support UTF-8, use iframe to support default OS encoding
			CreoleWiki.Iframe.get(wikiPath, contentHandler);
		} else {
			$.get(wikiPath, contentHandler); 
		}
	},

	getWikiFileUrl: function (wiki){
		return this.sitePath + wiki + this.suffix;
	},
	saveWiki: function(){
		if (!this.wikiName){
			alert("No wiki loaded!");
			return;
		}
		var wikiFilePath = this.getWikiFileUrl(this.wikiName);
		var data = $(this.input).val();
		if (this.options.crlf){
			data = data.replace(/\r?\n/g, '\r\n');
		}
		if (!saveFile(wikiFilePath, data, this.options.encoding)){
			alert("Save file failed: " + wikiFilePath);
		}
	},
	
	newWiki: function (wiki){
		if (!wiki){
			wiki = prompt("Please input Wiki Name?", "")
			if (!wiki){
				alert("Wiki name can not be empty!");
				return;
			}
		}
		$(this.main).html('');
		$(this.input).val('');
		this.loadWiki(wiki, true);
		this.wikiName = wiki;
		$(this.input).show();
	},

    render: function(data, contentPane) {
        if (!contentPane){
        	contentPane = this.main;
        }
        contentPane.innerHTML = '';
        this.creole.parse(contentPane, data);
        //$(contentPane).('img').each(function(){
        //});
    }
}

CreoleWiki.Site.prototype.constructor = CreoleWiki.Site;

CreoleWiki.error = function(msg){
	alert(msg);
	throw new Error(msg);
};

CreoleWiki.Iframe = {
	uid: 0,
	get: function(url, contentHandler){
		if ($.browser.msie && $.browser.version >= 8 && url.indexOf("file:") == 0){
			if (url.indexOf("file:///") == 0){
	              url = url.substr(8);
	        }
			var data = CreoleWiki.Iframe.ieLoadFile(url);
			contentHandler(data);
			return;
		}
	
		var id = CreoleWiki.Iframe.uid ++;
		var ifrid = 'ifr-id-' + id;
		$("body").append("<iframe src='javascript:void(0)' frameborder='0' width='0' height='0' id='" + ifrid + "'></iframe>");
		$("#" + ifrid).attr('src', url).load(function(){
			var data =  $(this).contents().find('pre').html() || "";
			contentHandler(data);
			$(this).remove();
		});
	},
	// throw exception if it can't do it, or a string of the content if successful
	ieLoadFile: function (filePath)
	{
		var fso = new ActiveXObject("Scripting.FileSystemObject");
		var file = fso.OpenTextFile(filePath,1);
		var content = file.ReadAll();
		file.Close();
		return content;
	}
};

CreoleWiki.Moniter = {
	currHash: '*',
	intervalID: null,
	start: function(){
	  with (CreoleWiki.Moniter){
		stop();
		if (window.location.hash != currHash){
			try {
				site.loadWiki(window.location.hash);
			} catch (e){
				alert(e);
			}
			currHash = window.location.hash;
		}
		intervalID = window.setInterval(start,10);
	  }
	},
	stop: function(){
	  with (CreoleWiki.Moniter){
		if (intervalID){
			window.clearInterval(intervalID);
			intervalID = null;
		}
	  }
	}
};

CreoleWiki.Favorite = {
	setHome: function(){
		$.cookie('home', site.getFullWikiName(), {expires: 3650 });
	},
	getHome: function(){
		var wiki = $.cookie('home') || '';
		return wiki == '#Special:Home'? '' : wiki;
	},
	setFavorite: function(){
		var favorite = $.cookie('favorite') || '';
		var wikis = favorite.split(',');
		if (!favorite){
			wikis.length = 0;
		}		
		if ($.inArray(site.getFullWikiName(), wikis) >= 0){
			return;
		}
		wikis.push(site.getFullWikiName());
		$.cookie('favorite', wikis.join(','), {expires: 3650 });
	},
	getFavorite: function(){
		var favorite = $.cookie('favorite') || '';
		if (!favorite){
			return "No favorites!";
		}
		var wikis = favorite.split(',');
		var html = "<ol>";
		$.each(wikis, function(n, wiki){
			html += '<li><a href="' + encodeURI(wiki) + '">' + wiki + '</a> <input type="button" value="X" onclick="javascript:CreoleWiki.Favorite.removeFavorite(\'' + wiki + '\');"/></li>';
		});
		html += "</ol>";
		return html;
	},
	removeFavorite: function(wiki){
		if (!wiki){
			return;
		}
		var favorite = $.cookie('favorite') || '';
		var wikis = favorite.split(',');
		wikis = jQuery.grep(wikis, function(value) {
			return value != wiki;
		});
		if (wikis.length){
			$.cookie('favorite', wikis.join(','), {expires: 3650 });
		} else {
			$.cookie('favorite', null);
		}
		site.loadWiki('#Special:Favorite');
	}
};

// saveFile function from [[http://www.tiddlywiki.com/|tiddlywiki]]
// to support UTF-8, only use javaSaveFile, the applet will be delay loaded.
function saveFile(fileUrl,content,encoding)
{
	return javaSaveFile(fileUrl,content,encoding);
}

function javaUrlToFilename(url)
{
	var f = 'file://';
    if (url.indexOf(f) == 0){
        url = url.substring(f.length);
    } 
	f = "//localhost";
	if(url.indexOf(f) == 0)
		url = url.substring(f.length);
	return url;
}

function doJavaSaveFile(filePath, content,encoding)
{
	try {
		if(document.applets["TiddlySaver"])
			return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath), encoding || "UTF-8", content);
	} catch(ex) {
	}
	try {
		var s = new java.io.PrintStream(new java.io.FileOutputStream(javaUrlToFilename(filePath)));
		s.print(content);
		s.close();
	} catch(ex) {
		return null;
	}
	return true;
}

function javaSaveFile(filePath, content, encoding)
{
	if (! $('#appletDiv').html()){
		$('#appletDiv').html("<applet name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1' height='1'></applet>");
	}
		
	javaSaveFile = doJavaSaveFile;
	return doJavaSaveFile(filePath, content, encoding);
}
